﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;

namespace RPGOnline.Controls.Map.Layers.Obstruction.Editors
{
    public partial class ObstructionEditorControl : UserControl
    {
        private Image m_backgroundImage;
        private MapCell m_mapCell;
        private MapTileset m_tileset;
        public event EventHandler<PixelClickedEventArgs> OnPixelClicked;

        public ObstructionEditorControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.Opaque, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.UserPaint, true);

            InitializeComponent();
        }

        public ObstructionLine HighlightedLine { get; set; }

        public void Update(MapTileset tileset, MapCell mapCell, int x, int y)
        {
            m_mapCell = mapCell;
            m_tileset = tileset;
            m_backgroundImage = new Bitmap(tileset.TileSize.Width, tileset.TileSize.Height);
            
            using(Graphics g = Graphics.FromImage(m_backgroundImage))
            {
                Rectangle destRectangle = new Rectangle(0, 0, tileset.TileSize.Width, tileset.TileSize.Height);
                Rectangle srcRectangle = new Rectangle(x*tileset.TileSize.Width, y*tileset.TileSize.Height,
                                                        tileset.TileSize.Width, tileset.TileSize.Height);

                g.DrawImage(tileset.TileSetImage, destRectangle, srcRectangle, GraphicsUnit.Pixel);
            }

            Width = (tileset.TileSize.Width + 2)*16;
            Height = (tileset.TileSize.Height + 2)*16;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                if (OnPixelClicked != null)
                    OnPixelClicked(this, new PixelClickedEventArgs((e.Location.X / 16) - 1, (e.Location.Y / 16) - 1, m_mapCell));
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (m_backgroundImage == null)
                return;

            RectangleF destRectangle = new RectangleF(16.0f, 16.0f, m_tileset.TileSize.Width * 16.0f, m_tileset.TileSize.Height * 16.0f);
            RectangleF srcRectangle = new RectangleF(0.0f, 0.0f, m_backgroundImage.Width, m_backgroundImage.Height);
            e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
            e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            e.Graphics.DrawImage(m_backgroundImage, destRectangle, srcRectangle, GraphicsUnit.Pixel);

            DrawGrid(e);
            DrawObstructionLines(e);
        }

        private void DrawObstructionLines(PaintEventArgs e)
        {
            e.Graphics.ScaleTransform(16, 16);
            e.Graphics.TranslateTransform(1.5f, 1.5f);

            Pen white = new Pen(Color.White, 1/16.0f);
            Pen red = new Pen(Color.Red, 1/16.0f);
            Pen lime = new Pen(Color.Lime, 1/16.0f);

            foreach (ObstructionLine obstructionLine in m_mapCell.ObstructionLines)
            {
                Pen lineColor = white;
                if (obstructionLine == HighlightedLine)
                    lineColor = red;

                foreach (ObstructionEdge obstructionEdge in obstructionLine.GetEdges(0, 0))
                {
                    e.Graphics.DrawLine(lineColor, obstructionEdge.StartPoint.X, obstructionEdge.StartPoint.Y,
                                        obstructionEdge.EndPoint.X, obstructionEdge.EndPoint.Y);

                    DrawKeyPoint(e, obstructionEdge.StartPoint, Brushes.White);
                    DrawKeyPoint(e, obstructionEdge.EndPoint, Brushes.White);
                    DrawNormal(e, obstructionEdge, lime);
                }
            }

            e.Graphics.ResetTransform();
        }

        private void DrawNormal(PaintEventArgs e, ObstructionEdge obstructionEdge, Pen pen)
        {
            Vector2 startToEnd = obstructionEdge.EndPoint - obstructionEdge.StartPoint;
            Vector2 middlePoint = obstructionEdge.StartPoint + (startToEnd*0.5f);
            Vector2 normal = obstructionEdge.CalculateNormal();
            normal.Normalize();

            Vector2 normalArrow = middlePoint + (normal*startToEnd.Length());

            e.Graphics.DrawLine(pen, middlePoint.X, middlePoint.Y, normalArrow.X, normalArrow.Y);
        }

        private void DrawKeyPoint(PaintEventArgs e, Vector2 point, Brush brush)
        {
            RectangleF startPointRect = new RectangleF(point.X, point.Y, 0, 0);
            startPointRect.Inflate(2.5f / 16.0f, 2.5f / 16.0f);

            e.Graphics.FillRectangle(brush, startPointRect);
        }

        private void DrawGrid(PaintEventArgs e)
        {
            for(int y = 0; y <= Height; y += 16)
            {
                e.Graphics.DrawLine(Pens.Gray, 0, y, Width, y);
            }

            for (int x = 0; x <= Width; x += 16)
            {
                e.Graphics.DrawLine(Pens.Gray, x, 0, x, Height);
            }
        }
    }
}
